﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Api;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Security;
using Xenta.Structs;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Creates a log record.
    /// </summary>
    public class CreateLogRecord : CreateAuditable<LogRecordEntity>,
        IApiOperation
    {
        #region Properties

        /// <summary>
        ///   Gets or sets the source.
        /// </summary>
        public string Source
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the description.
        /// </summary>
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the flags.
        /// </summary>
        public LogRecordFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Source))
                return Err.Of<LogRecordEntity>().NotValid("Source");
            return base.Validate(uow);
        }

        protected override void Construct(IUnitOfWork uow, LogRecordEntity entity)
        {
            base.Construct(uow, entity);

            entity.Source = Source.TrimToLen(100);
            entity.Description = StringHelper.EnsureNotNull(Description).TrimToLen(1000);
            entity.Text = StringHelper.EnsureNotNull(Text);
            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Updates the log record.
    /// </summary>
    public class UpdateLogRecord : UpdateAuditable<LogRecordEntity>
    {
        #region Properties

        /// <summary>
        ///   Gets or sets the source.
        /// </summary>
        public string Source
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the description.
        /// </summary>
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the flags.
        /// </summary>
        public LogRecordFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Source))
                return Err.Of<LogRecordEntity>().NotValid("Source");
            return base.Validate(uow);
        }

        protected override void Revise(IUnitOfWork uow, LogRecordEntity entity)
        {
            base.Revise(uow, entity);

            entity.Source = Source.TrimToLen(100);
            entity.Description = StringHelper.EnsureNotNull(Description).TrimToLen(1000);
            entity.Text = StringHelper.EnsureNotNull(Text);
            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the log record.
    /// </summary>
    public class DeleteLogRecord : DeleteEntity<LogRecordEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        #endregion
    }

    /// <summary>
    /// Gets the log record by identifier.
    /// </summary>
    public class GetLogRecord : GetEntity<LogRecordEntity>,
        IApiOperation
    {
    }

    #endregion

    #region __Search__

    /// <summary>
    ///   Searches over the log record collection.
    /// </summary>
    public class SearchLogRecords : SearchOperation<LogRecordEntity>,
        IApiOperation
    {
        #region Ctors

        /// <summary>
        ///   Initializes a new class instance.
        /// </summary>
        public SearchLogRecords()
        {
            Term = SearchTerm.Empty;
            SortDir = SortDirection.Ascending;
            SortBy = new []
            {
                LogRecordSortBy.ID
            };
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the search term.
        /// </summary>
        public SearchTerm Term
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the flag mask.
        /// </summary>
        public LogRecordFlags FlagMask
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the creation date 'from'.
        /// </summary>
        public DateTime? CreatedFrom
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the creation date 'to'.
        /// </summary>
        public DateTime? CreatedTo
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the sort direction.
        /// </summary>
        public SortDirection SortDir
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the sort by.
        /// </summary>
        public LogRecordSortBy[] SortBy
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<LogRecordEntity> Build(IUnitOfWork uow, IQueryable<LogRecordEntity> query)
        {
            query = base.Build(uow, query);
            query = query.FilterByFlags(x => (int)x.Flags, (int)FlagMask);
            query = query.FilterByDateRange(x => x.CreatedOn, CreatedFrom, CreatedTo);
            switch(Term.Mode)
            {
                case SearchTerm.SearchMode.StartsWith:
                    query = query.Where(x => x.Source.StartsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.EndsWith:
                    query = query.Where(x => x.Source.EndsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Contains:
                    query = query.Where(x => x.Source.Contains(Term.Keyword) ||
                        x.Description.Contains(Term.Keyword) ||
                        x.Text.Contains(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Equals:
                    query = query.Where(x => x.Source.Equals(Term.Keyword));
                    break;
            }
            if(SortBy != null)
            {
                for(int i = 0; i < SortBy.Length; i++)
                {
                    switch(SortBy[i])
                    {
                        case LogRecordSortBy.Source:
                            query = query.OrderBy(x => x.Source, SortDir, i != 0);
                            break;
                        case LogRecordSortBy.CreatedOn:
                            query = query.OrderBy(x => x.CreatedOn, SortDir, i != 0);
                            break;
                        default:
                            query = query.OrderBy(x => x.EntityID, SortDir, i != 0);
                            break;
                    }
                }
            }
            return query;
        }

        #endregion
    }

    #endregion

    #region __Bulk__

    /// <summary>
    /// Bulk deletes log records.
    /// </summary>
    public class DeleteLogRecords : Operation<Int32>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        /// <summary>
        ///   Gets or sets the creation date "from".
        /// </summary>
        public DateTime? CreatedFrom
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the creation date "to".
        /// </summary>
        public DateTime? CreatedTo
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in uow.Execute(new SearchLogRecords
            {
                CreatedFrom = CreatedFrom,
                CreatedTo = CreatedTo
            }).Result)
            {
                uow.Execute(new DeleteLogRecord
                {
                    EntityID = i.EntityID
                });
                result++;
            }
        }

        #endregion
    }

    #endregion

    #region __Misc__

    /// <summary>
    ///   Creates a log record using exception object.
    /// </summary>
    public class CreateLogRecordFromException : Operation<LogRecordEntity>
    {
        #region Properties

        /// <summary>
        ///   Gets or sets the exception.
        /// </summary>
        public Exception Ex
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out LogRecordEntity result)
        {
            result = Ex != null
                ? uow.Execute(new CreateLogRecord
                {
                    Source = Ex.Source,
                    Description = Ex.Message,
                    Text = Ex.ToString(),
                    Flags = LogRecordFlags.Error | LogRecordFlags.High
                }).Result
                : null;
        }

        #endregion
    }

    #endregion
}
